package net.peelmeagrape.hibernate;

import net.peelmeagrape.hibernate.xmlgen.*;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;

/**
 * Defines a polymorphic association to classes from multiple tables.
 * This type of mapping always requires more than one column. The first
 * column ({@link #classnameColumn()})
 * holds the type of the associated entity. The remaining columns
 * ({@link #columnMapping()} )
 * hold the identifier. It is impossible to specify a foreign key constraint
 * for this kind of association, so this is most certainly not meant as the
 * usual way of mapping (polymorphic) associations. You should use this only
 *  in very special cases (eg. audit logs, user session data, etc).
 * <br/>
 * <br/>
 *  The {@link #metaValue()} attribute lets the application specify a custom type that maps database
 * column values to persistent classes which have identifier properties of the type specified by id-type.
 * You must specify the mapping from values of the meta-type to class names.
 */
@Target({METHOD,FIELD}) @Retention(RUNTIME)
@XmlElement(name="any")
@AddPropertyNameAsAttribute(name="name")
public @interface Any
{
    @XmlAttribute("id-type") String idType();
    @XmlAttribute("meta-type") String metaType();

    /**
     * The strategy Hibernate should use for accessing the property value. This may be one of
     * 'property', 'field', 'embedded', or the name of a subclass of {@link org.hibernate.property.PropertyAccessor}.
     */
    @XmlAttribute String access() default "property";
    @XmlAttribute boolean update() default true;
    @XmlAttribute boolean insert() default true;

    @XmlAttribute String cascade() default "";
    @XmlAttribute String index() default "";

    @XmlAttribute("optimistic-lock") boolean optimisticLock() default true;
    @XmlAttribute boolean lazy() default false;
    @XmlAttribute String node() default "";

    @ChildElement(0) Meta[] meta() default {};

    /**
     * Map class names to values.
     */
    @ChildElement(1) MetaValue[] metaValue() default {};
    /**
     * The column which holds the class name of the referenced entity.
     */
    @ChildElement(2) Column classnameColumn();
    /**
     * Referenced entity's identifier values are stored in these column(s).
     */
    @ChildElement(3) Column[] columnMapping() default {};

    @FindParentElement(name="natural-id") boolean naturalId() default false;
    @FindParentElement(
        name="join",
        idAttributeName = "table",
        reorderNewParent = "any|sql-insert?,sql-update?,sql-delete?"
    )
        String[] join() default {};
}
